package com.mahees.portfolio.controller

import grails.validation.ValidationException;
import java.util.List;
import org.codehaus.groovy.grails.web.json.JSONArray;

import com.mahees.portfolio.controller.SoftwareProjectCommand;
import com.mahees.portfolio.domain.DevelopmentTool;
import com.mahees.portfolio.domain.DevelopmentToolTypeEnum;
import com.mahees.portfolio.domain.SoftwareProject;
import com.mahees.portfolio.domain.SoftwareProjectTypeEnum;
import com.mahees.portfolio.service.ProjectService;

import grails.converters.JSON;
import grails.test.*
import grails.web.JSONBuilder;

class SoftwareProjectControllerTests extends ControllerUnitTestCase {

	SoftwareProjectCommand cmd
	List<DevelopmentTool> developmentTools

	protected void setUp() {
		super.setUp()

		cmd = new SoftwareProjectCommand()
		mockForConstraintsTests(SoftwareProjectCommand, [cmd]);

		controller.metaClass.render = { Map map, Closure c ->
			mockResponse.status = map.status
			new JSONBuilder().build(c).render(mockResponse)
		}
		mockRequest.contentType = 'application/json';
		//http://grails.org/doc/2.0.x/ref/Servlet%20API/request.html
		controller.request.format = 'json'
		controller.params.format = 'json'
		controller.request.contentType = "application/json"

		mockDomain(DevelopmentTool);

		developmentTools = [
			new DevelopmentTool(name : 'Eclipse',
			description : 'Built in Java, many plugins available',
			url : 'http://www.eclipse.org/',
			toolType : DevelopmentToolTypeEnum.IDE
			).save(failOnError : true),
			new DevelopmentTool(name : 'SpringSource Tool Suite',
			url : 'http://www.springsource.com/developer/sts',
			toolType : DevelopmentToolTypeEnum.IDE
			).save(failOnError : true)
		]

	}

	protected void tearDown() {
		super.tearDown()
	}

	void testSave_TryToSaveWithBadProjectType_ValidationFailsAndReturns500() {
		def populate = [:]
		populate.name = 'Health Plus Systems'
		populate.url = 'https://healthplussystems.com'
		populate.description = 'project i worked on'
		populate.projectType = 'WE' //should be WEB
		populate.developmentTools = [[id : 1]]as JSON

		mockRequest.content = "{ name : '${populate.name}', url : '${populate.url}', description : '${populate.description}', projectType : '${populate.projectType}', developmentTools : ${populate.developmentTools} }";

		def inputParams = controller.request.JSON

		cmd.name = inputParams.name
		cmd.url = inputParams.url
		cmd.description = inputParams.description
		cmd.projectType = inputParams.projectType
		cmd.developmentTools = inputParams.developmentTools

		controller.save(cmd);

		println controller.response.contentAsString
		assert controller.response.status == 500
		JSONArray result = JSON.parse(controller.response.contentAsString);
		assert result.size() == 1

	}


	void testSave_HappyPath_SendsToServiceAsExpected() {
		def projectServiceControl = mockFor(ProjectService);
		projectServiceControl.demand.saveSoftwareProject(1..1) { SoftwareProject softwareProject, def hasManyOptions ->
			assert softwareProject.validate();

			assert softwareProject.name == 'Health Plus Systems'
			assert softwareProject.url == 'https://healthplussystems.com'
			assert softwareProject.description == 'project i worked on'
			assert softwareProject.projectType == SoftwareProjectTypeEnum.WEB

			assert hasManyOptions.size() == 1
			assert hasManyOptions.developmentTools[0] == developmentTools[0]
			return true
		}
		controller.projectService = projectServiceControl.createMock()

		def populate = [:]
		populate.name = 'Health Plus Systems'
		populate.url = 'https://healthplussystems.com'
		populate.description = 'project i worked on'
		populate.projectType = 'WEB'
		populate.developmentTools = [[id : 1]]as JSON


		mockRequest.content = "{ name : '${populate.name}', url : '${populate.url}', description : '${populate.description}', projectType : '${populate.projectType}', developmentTools : ${populate.developmentTools} }";

		def inputParams = controller.request.JSON

		cmd.name = inputParams.name
		cmd.url = inputParams.url
		cmd.description = inputParams.description
		cmd.projectType = inputParams.projectType
		cmd.developmentTools = inputParams.developmentTools

		controller.save(cmd);

		assert controller.response.status == 200
		projectServiceControl.verify()
	}

	void testTRUETDDSave_HappyPath_SendsToServiceAsExpected() {

		def projectServiceControl = mockFor(ProjectService);
		projectServiceControl.demand.saveSoftwareProject(1..1) { SoftwareProject softwareProject, def hasManyOptions ->
			assert softwareProject.validate();

			assert softwareProject.name == 'Health Plus Systems'
			assert softwareProject.url == 'https://healthplussystems.com'
			assert softwareProject.description == 'project i worked on'
			assert softwareProject.projectType == SoftwareProjectTypeEnum.WEB

			assert hasManyOptions.size() == 1
			assert hasManyOptions.developmentTools[0] == developmentTools[0]
			return true
		}
		controller.metaClass.projectService = projectServiceControl.createMock()

		controller.metaClass.save { SoftwareProjectCommand cmd ->
			if (!cmd.validate()) {
				withFormat {
					json {
						render(contentType: "application/json", status: 500) {
							array {
								cmd.errors.allErrors.each { e ->
									err(field: e.field, value: e.rejectedValue, message: e.defaultMessage)
								}
							}
						}
					}
				}
			}

			def hasManyOptions = [developmentTools:[]];
			cmd.developmentTools.each {
				DevelopmentTool tool = DevelopmentTool.get(it.id)
				if (tool) {
					hasManyOptions.developmentTools.add(tool);
				}
			}

			SoftwareProject softwareProject = new SoftwareProject(
					name : cmd.name,
					description : cmd.description,
					url : cmd.url,
					projectType : cmd.projectType as SoftwareProjectTypeEnum
					)

			try {
				controller.projectService.saveSoftwareProject(softwareProject, hasManyOptions);
				withFormat {
					json {
						render(contentType: "application/json", status: 200)
					}
				}
			}
			catch (ValidationException ex) {
			}
			catch (RuntimeException ex) {
			}
		}

		def populate = [:]
		populate.name = 'Health Plus Systems'
		populate.url = 'https://healthplussystems.com'
		populate.description = 'project i worked on'
		populate.projectType = 'WEB'
		populate.developmentTools = [[id : 1]]as JSON


		mockRequest.content = "{ name : '${populate.name}', url : '${populate.url}', description : '${populate.description}', projectType : '${populate.projectType}', developmentTools : ${populate.developmentTools} }";

		def inputParams = controller.request.JSON

		cmd.name = inputParams.name
		cmd.url = inputParams.url
		cmd.description = inputParams.description
		cmd.projectType = inputParams.projectType
		cmd.developmentTools = inputParams.developmentTools

		controller.save(cmd);

		assert controller.response.status == 200
		projectServiceControl.verify()
	}
}